﻿using System;
using System.Linq;
using System.Collections.Generic;
using MF.Networker;

namespace MF.Networker
{
    public class ConcurrentQueue<T> : IProducer<T>, IConsumer<T>
    {
        private Queue<T> _produceQueue;
        private Queue<T> _consumeQueue;
        private object _produceMutex;
        private object _consumeMutex;

        public ConcurrentQueue()
        {
            this._produceQueue = new Queue<T>();
            this._consumeQueue = new Queue<T>();
            this._consumeMutex = new object();
            this._produceMutex = new object();
        }

        #region IProducer<T> 成员

        public void Produce(T item)
        {
            lock (this._produceMutex)
            {
                this._produceQueue.Enqueue(item);
            }
        }

        #endregion

        #region IConsumer<T> 成员

        /// <summary>
        /// 队列为空的情况下，将阻塞线程
        /// </summary>
        public T Consume()
        {
            if (this._consumeQueue.Count > 0)
            {
                lock (this._consumeMutex)
                {
                    if (this._consumeQueue.Count > 0)
                    {
                        return this._consumeQueue.Dequeue();
                    }
                    else
                    {
                        this.TryExchange();
                    }
                }

            }
            else
            {
                this.TryExchange();
            }

            //递归调用
            return this.Consume();
        }

        #endregion

        private void TryExchange()
        {
            while (!this.CanExchange())
            {
                System.Threading.Thread.Sleep(10);      //这里暂时简单的使用sleep，而没使用AutoResetEvent
            }

            if (this.CanExchange())
            {
                lock (this._produceMutex)
                {
                    if (this.CanExchange())
                    {
                        var temp = this._produceQueue;
                        this._produceQueue = this._consumeQueue;
                        this._consumeQueue = temp;
                    }
                }
            }
        }

        private bool CanExchange()
        {
            return this._produceQueue.Count > 0 && this._consumeQueue.Count == 0;
        }
    }
}
